#include "UpdataLogic.h"
#include "Request.h"
#include "AuClient.h"
#include "FileUtil.h"
#include "Md5Util.h"
#include <libgen.h>
#include <sys/stat.h>
#include "ConfigUtil.h"
UpdataLogic::UpdataLogic(/* args */)
{
}

UpdataLogic::~UpdataLogic()
{
}

bool UpdataLogic::execute(map<string, string> param)
{     
    //向服务端发送请求，下载zip更新文件
    map<string,string> paramMap;
    paramMap["version"]=param["version"];
    paramMap["type"]="1";
    Request request((char*)"192.168.38.128",8080,paramMap);
    
    AuClient client;
    Response* response=client.execute(request);

    //将服务端返回的文件字节流写入到客户端文件中
    if (!response->getSuccess())
    {
        return false;
    }
    FileContent* fileContent=response->getFileContent();
    writeFile((char*)"./bin/updata.zip",fileContent->content,fileContent->length);
    
    //校验文件
    //对下载的文件做加密
    const char* md5=getMd5OfFile((char*)"./bin/updata.zip");
    string md5Str=string(md5);

    string sign=param["sign"];
    if (md5Str.compare(sign)!=0)
    {
        cout<<"更新文件被破坏，请重新下载"<<endl;
        return false;
    }

    //解压更新文件的zip
    unzip((char*)"./bin/updata.zip");

    //备份原程序，打包为zip


    //根据zip中的ini文件替换更新文件
    replaceFile("./updata/config.ini",param["installPath"]);

    //删除备份


    //修改客户端版本号
    ConfigUtil::updateValue("./config/updata.ini","config","version",param["version"]);
    
    return false;
}

void UpdataLogic::replaceFile(string configPath, string installPath)
{
    GKeyFile* keyFile = g_key_file_new();
    gboolean flag = g_key_file_load_from_file(keyFile,configPath.c_str(),G_KEY_FILE_NONE,NULL);
    int num = g_key_file_get_integer(keyFile,"config","updateNum",NULL);
    for(int i=0;i<num;i++)
    {
        string groupName = "file"+to_string(i);
        // srcPath指的不是客户端原本的这个文件所在，指的是你下载下来的文件路径
        string srcPath = g_key_file_get_string(keyFile,groupName.c_str(),"srcPath",NULL);
        // /1/1.txt
        string destPath = g_key_file_get_string(keyFile,groupName.c_str(),"destPath",NULL);
        // /usr/local/updateSystem/client/1/1.txt
        string replacePath = installPath + destPath;
        cout << groupName << ": srcPath=" << srcPath << "  destPath" << replacePath << endl;
        this->copyFile(srcPath.c_str(),replacePath.c_str());
    }
}

 // 强制复制文件替换文件
gboolean UpdataLogic::copyFile(const char *srcfile, const char *dstfile)
{
    gboolean result = TRUE;
    FILE *fpsrc = fopen(srcfile, "rb");
    if (fpsrc == NULL)
    {
        g_warning("%s读取失败", srcfile);
        return FALSE;
    }
    fseek(fpsrc, 0, SEEK_END);
    int totalsize = ftell(fpsrc);
    rewind(fpsrc);

    char *dstDir = g_path_get_dirname(dstfile);
    if (!createDirectory(dstDir)) {
        g_free(dstDir);
        fclose(fpsrc);
        return FALSE;
    }
    g_free(dstDir);

    FILE *fpdst = fopen(dstfile, "wb");
    if (fpdst == NULL)
    {
        fclose(fpsrc);
        //g_warning("%s写入失败", dstfile);
        g_warning("%s创建失败: %s", dstfile, strerror(errno));
        return FALSE;
    }
    // 循环写入
    char* buffer = (char*)malloc(totalsize);
    int bytes_read = 0, bytes_write = 0;
    while ((bytes_read = fread(buffer + bytes_read, sizeof(char), 128, fpsrc)) > 0)
    {
        bytes_write = fwrite(buffer + bytes_write, sizeof(char), bytes_read, fpdst);
        if (bytes_read != bytes_write)
        {
            g_warning("写入%s失败", dstfile);
            result = FALSE;
            break;
        }
    }

    fclose(fpsrc);
    fclose(fpdst);
    if (buffer[1] == 'E' && buffer[2] == 'L' && buffer[3] == 'F')
    {
        struct stat stdst;
        // 获取文件权限
        if (stat(dstfile, &stdst) < 0)
        {
            g_warning("stat %s error", dstfile);
            free(buffer);
            return FALSE;
        }
        // 添加可执行权限
        chmod(dstfile, stdst.st_mode | S_IXUSR | S_IRGRP | S_IXOTH);
    }
    free(buffer);
    return TRUE;
}

// 创建目录路径的函数
int UpdataLogic::createDirectory(const char *path) {
    char tempPath[1024];
    struct stat st = {0};
    // 检查输入路径是否为空
    if (path == NULL || *path == '\0') {
        g_warning("路径为空!");
        return -1;
    }
 
    // 复制输入路径到临时变量，因为我们会修改它
    strncpy(tempPath, path, sizeof(tempPath));
 
    // 逐个创建目录路径中的每个组件
    while (strlen(tempPath) > 0) {
        // 检查当前路径是否存在
        if (stat(tempPath, &st) != 0) {
            // 如果不存在，尝试创建它
            if (mkdir(tempPath, 0755) != 0) {
                // 创建目录失败，如果不是因为目录已存在，则报错
                if (errno != EEXIST) {
                    g_warning("创建目录失败!,原因%s",strerror(errno));
                }
            } else {
                // 成功创建目录，打印调试信息（可选）
                printf("创建目录: %s\n", tempPath);
            }
        } else if (!(st.st_mode & S_IFDIR)) {
            // 路径存在但不是目录，报错
            fprintf(stderr, "路径 %s 不是一个目录\n", tempPath);
            return -1;
        }
 
        // 获取当前路径的父目录
        char *parentDir = dirname(tempPath);
 
        // 如果父目录是根目录（"/"或"C:\\"在Windows上），则停止循环
        if (strcmp(parentDir, "/") == 0 || strcmp(parentDir, "\\") == 0) {
            break;
        }
 
        // 继续处理父目录
        //tempPath = parentDir;
        strncpy(tempPath, parentDir, sizeof(tempPath));
    }
 
    return TRUE;
}